<template>
  <el-dialog title="自定义节点" width="1000px" 
  :visible.sync="dialogVisible" 
  :append-to-body="true"
  :center="true"
  :close-on-click-modal="false"
  @opened="handleDialogOpened">
    <el-row :gutter="20">
      <el-col :span="6" class='groupColumn'>
        <el-collapse v-model="activeGroupNames" class='groupCollapse'>
          <el-collapse-item v-for="nodeGroup of graphNodeGroups" :key="nodeGroup.groupName" 
          :title="nodeGroup.groupTitle" :name="nodeGroup.groupName">
            <el-table :data="nodeGroup.nodeDatas" :ref="nodeGroup.groupName"
            :show-header="false" 
            highlight-current-row 
            stripe
            border
            :row-class-name="groupRowClassName"
            @row-click="handleGraphRowClick"
            style="width: 100%">
              <el-table-column :formatter="formatNodeData"></el-table-column>
            </el-table>
          </el-collapse-item>
        </el-collapse>
        <div>
          <el-button type="warning" @click="handleNewNode">新建节点</el-button>
          <el-button type="danger" @click="handleDeleteNode">删除节点</el-button>
        </div>
      </el-col>
      <el-col :span="12" class='nodeColumn'>
        <el-collapse v-model="activeNames">
          <el-collapse-item title="基本属性" name="1">
            <el-form :model="form" :rules="formRules" ref="ruleForm">
              <el-form-item label="节点名称" :label-width="formLabelWidth" prop="shape">
                <el-input v-model="form.shape" :disabled='currentNode !== null'></el-input>
              </el-form-item>
              <el-form-item label="是否可连接" :label-width="formLabelWidth" prop="magnet">
                <el-switch v-model="form.magnet" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
              </el-form-item>

              <el-form-item label="节点高度" :label-width="formLabelWidth" prop="height">            
                <el-input-number v-model="form.height"></el-input-number>
              </el-form-item>
              <el-form-item label="节点宽度" :label-width="formLabelWidth" prop="width">
                <el-input-number v-model="form.width"></el-input-number>
              </el-form-item>
              <el-form-item label="是否允许调整" :label-width="formLabelWidth">
                <el-switch v-model="form.data.enableResize" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
              </el-form-item>
              
              <el-form-item label="最小高度" :label-width="formLabelWidth" prop="minHeight" v-show="form.data.enableResize">            
                <el-input-number v-model="form.data.minHeight"></el-input-number>
              </el-form-item>
              <el-form-item label="最大高度" :label-width="formLabelWidth" prop="maxHeight" v-show="form.data.enableResize">            
                <el-input-number v-model="form.data.maxHeight"></el-input-number>
              </el-form-item>
              <el-form-item label="最小宽度" :label-width="formLabelWidth" prop="minWidth" v-show="form.data.enableResize">            
                <el-input-number v-model="form.data.minWidth"></el-input-number>
              </el-form-item>
              <el-form-item label="最大宽度" :label-width="formLabelWidth" prop="maxWidth" v-show="form.data.enableResize">            
                <el-input-number v-model="form.data.maxWidth"></el-input-number>
              </el-form-item>

              <el-form-item label="metaType" :label-width="formLabelWidth" prop="data.metaType">
                <el-select v-model="form.data.metaType" filterable placeholder="请选择" @change="handleMetaTypeChange">
                  <el-option v-for="item in metaTypeOptions" 
                  :key="item.value" :label="item.label" :value="item.value"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="metaName" :label-width="formLabelWidth" prop="data.metaName">
                <el-input v-model="form.data.metaName" disabled></el-input>
              </el-form-item>
              <el-form-item label="量测信息" :label-width="formLabelWidth" v-show="isMeasureType">
                <measure-panel ref="measurePanel"></measure-panel>
              </el-form-item>
              <el-form-item label="所属节点组" :label-width="formLabelWidth" prop="data.group">
                <el-select v-model="form.data.group" filterable placeholder="请选择">
                  <el-option v-for="item in stencilGroupOptions" 
                  :key="item.name" :label="item.title" :value="item.name"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="描述信息" :label-width="formLabelWidth" prop="data.desc">
                <el-input v-model="form.data.desc" autocomplete="off"></el-input>
              </el-form-item>
            </el-form>
          </el-collapse-item>
          <el-collapse-item title="片段信息" name="2">
            <markup-panel ref="markupPanel"></markup-panel>
          </el-collapse-item>
          <el-collapse-item title="链接桩" name="4">
            <port-panel ref="portPanel"></port-panel>
          </el-collapse-item>
        </el-collapse>
      </el-col>      
      <el-col :span="6">
        <div id='nodeGraphContainer'></div>
      </el-col>
    </el-row>

    <div slot="footer">
      <el-button type="info" @click="handleViewAttrsConfig">属性配置说明</el-button>
      <el-button type="success" @click="handleVerified">验 证</el-button>
      <el-button type="primary" @click="handleSave">保 存</el-button>
      <el-button type="warning" @click="dialogVisible = false">关 闭</el-button>
    </div>

    <attrs-desc-dialog ref="attrsDescDialog"></attrs-desc-dialog>
  </el-dialog>
</template>

<script>
var _ = require('lodash')
import { Graph } from '@antv/x6/lib/index'
import ConfigUtil from '@/utils/graph-utils/configUtil'
import ConstantUtil from '@/utils/graph-utils/constantUtil'
import RegisterUtil from '@/utils/graph-utils/registerUtil'
import UIUtil from '@/utils/graph-utils/uiUtil'
import { addGraphNode, updateGraphNode, deleteGraphNode, getGraphNodes } from '@/api/draw.js'
import MarkupPanel from '@/views/drawTool/dialog/component/markup-panel.vue'
import MeasurePanel from '@/views/drawTool/dialog/component/measure-panel.vue'
import PortPanel from '@/views/drawTool/dialog/component/port-panel.vue'
import AttrsDescDialog from '@/views/drawTool/dialog/attrs-desc-dialog.vue'

export default {
  name: 'CreateNodeDialog',
  components: { MarkupPanel, MeasurePanel, PortPanel, AttrsDescDialog },
  data() {
    var validateShape = (rule, value, callback) => {
      const pattern = /^[a-zA-Z][a-zA-Z_0-9$]*$/
      if (!pattern.test(value)) {
        return callback(new Error('请输入以字母开头，不包含汉字的字符串'))
      }
      callback()
    }

    return {
      dialogVisible: false,
      nodeGraph: null,

      // 已保存的图形节点
      graphNodeGroups: [],
      activeGroupNames: [],
      currentNode: null, // 当前所选中的节点

      activeNames: ['1'],
      form: {
        shape: '',
        magnet: false,
        width: 20,
        height: 20,
        data: {
          enableResize: false,
          minWidth: '',
          maxWidth: '',
          minHeight: '',
          maxHeight: '',
          metaType: '',
          metaName: '',
          group: '',
          desc: ''
        }
      },
      formRules: {
        shape: [
          { required: true, validator: validateShape, trigger: 'change' }
        ],
        magnet: [
          { required: true, message: '请选择是否可链接', trigger: 'change' }
        ],
        width: [
          { required: true, message: '请选择节点宽度', trigger: 'change' }
        ],
        height: [
          { required: true, message: '请选择节点高度', trigger: 'change' }
        ],
        data: {
          metaType: [
            { required: true, message: '请选择节点类型', trigger: 'change' }
          ],
          metaName: [
            { required: true, message: '请选择节点类型名称', trigger: 'change' }
          ],
          group: [
            { required: true, message: '请选择节点分组', trigger: 'change' }
          ],
          desc: [
            { required: true, message: '请输入节点描述', trigger: 'change' }
          ]
        }
      },
      formLabelWidth: '120px',

      styleObject: {}
    }
  },
  computed: {
    metaTypeOptions() {
      return ConfigUtil.getMetaTypes()
    },

    stencilGroupOptions() {
      return ConfigUtil.getStencilGroups()
    },

    isMeasureType() {
      return ConstantUtil.isMeasureType(this.form.data.metaType)
    }
  },
  methods: {
    showDialog() {
      this.dialogVisible = true
    },

    // 初始化对话框
    initDialog() {
      this.initNodeGroup()
      this.initNodeAttr()
      this.initGraph()
    },

    initNodeGroup() {
      const self = this
      self.graphNodeGroups = []
      const groups = ConfigUtil.getStencilGroups()
      for (const group of groups) {
        self.graphNodeGroups.push({
          groupName: group.name,
          groupTitle: group.title,
          nodeDatas: []
        })
        self.activeGroupNames.push(group.name)
      }
      getGraphNodes().then(response => {
        const graphNodes = response.data
        for (const graphNode of graphNodes) {
          const index = self.graphNodeGroups.findIndex(value => {
            return value.groupName === graphNode.groupName
          })
          if (index !== -1) {
            self.graphNodeGroups[index].nodeDatas.push(graphNode)
          }
        }
      })
    },

    initNodeAttr() {
      this.initConfigOptions()
    },

    initGraph() {
      this.nodeGraph = new Graph({
        container: document.getElementById('nodeGraphContainer'),
        width: 200,
        height: 500,
        background: {
          color: '#333b50' // 设置画布背景颜色
        },
        grid: {
          size: 10,
          visible: true
        }
      })
    },

    handleDialogOpened() {
      this.initDialog()
      this.currentNode = null
    },

    getInitOptions() {
      return {
        form: {
          shape: '',
          magnet: false,
          width: 20,
          height: 20,
          data: {
            enableResize: false,
            minWidth: '',
            maxWidth: '',
            minHeight: '',
            maxHeight: '',
            metaType: '',
            metaName: '',
            group: '',
            desc: ''
          }
        },
        markup: [],
        attrs: {}
      }
    },

    // 初始化节点配置
    initConfigOptions() {
      const initOptions = this.getInitOptions()
      this.form = _.cloneDeep(initOptions.form)
      const markup = _.cloneDeep(initOptions.markup)
      const attrs = _.cloneDeep(initOptions.attrs)
      this.$refs.markupPanel.setMarkupInfo(markup, attrs)
    },

    setConfigOptions(content) {
      const config = JSON.parse(content)
      this.form.shape = config.shape
      this.form.magnet = config.magnet
      this.form.width = config.width
      this.form.height = config.height
      const configData = _.cloneDeep(config.data)
      if (!_.has(configData, 'enableResize')) {
        _.set(configData, 'enableResize', false)
      }
      if (!_.has(configData, 'minWidth')) {
        _.set(configData, 'minWidth', '')
      }
      if (!_.has(configData, 'maxWidth')) {
        _.set(configData, 'maxWidth', '')
      }
      if (!_.has(configData, 'minHeight')) {
        _.set(configData, 'minHeight', '')
      }
      if (!_.has(configData, 'maxHeight')) {
        _.set(configData, 'maxHeight', '')
      }
      this.form.data = configData

      const markup = _.cloneDeep(config.markup)
      const attrs = _.cloneDeep(config.attrs)

      this.$refs.markupPanel.setMarkupInfo(markup, attrs)
      if (ConstantUtil.isMeasureType(this.form.data.metaType)) {
        this.$refs.measurePanel.setMeasureInfo(config.data.rows)
      }
      if (config.ports) {
        this.$refs.portPanel.setPortInfo(config.ports)
      } else {
        this.$refs.portPanel.setPortInfo([])
      }
    },

    getRegisterOptions() {
      const self = this
      let options = {}
      self.$refs.ruleForm.validate(valid => {
        if (valid) {
          options = _.cloneDeep(this.form)
          // 过滤掉多余的data属性
          if (!options.data.enableResize || options.data.minWidth === 0) {
            _.unset(options.data, 'minWidth')
          }
          if (!options.data.enableResize || options.data.maxWidth === 0) {
            _.unset(options.data, 'maxWidth')
          }
          if (!options.data.enableResize || options.data.minHeight === 0) {
            _.unset(options.data, 'minHeight')
          }
          if (!options.data.enableResize || options.data.maxHeight === 0) {
            _.unset(options.data, 'maxHeight')
          }

          // 测点类型时，需要获取测点信息
          if (ConstantUtil.isMeasureType(this.form.data.metaType)) {
            const rows = this.$refs.measurePanel.getMeasureInfo()
            options.data.rows = _.cloneDeep(rows)
          }

          // 获取片段和属性信息
          const markupInfo = this.$refs.markupPanel.getMarkupInfo()
          options.markup = markupInfo.markup
          options.attrs = markupInfo.attrs

          const portInfo = this.$refs.portPanel.getPortInfo()
          if (portInfo) {
            options.ports = _.cloneDeep(portInfo)
          }
        }
      })

      return options
    },

    // 节点配置项是否发生变化
    isConfigModified() {
      let modified = false
      const configOption = this.getRegisterOptions()
      const configOptionText = ConstantUtil.stringifyJson(configOption)
      // 获取当前所选中的节点，如果为空则是新建节点
      if (this.currentNode) {
        const nodeConfig = this.currentNode.content
        modified = nodeConfig !== configOptionText
      } else {
        const initOption = this.getInitOptions()
        const initOptionText = ConstantUtil.stringifyJson(initOption)
        modified = initOptionText !== configOptionText
      }
      return modified
    },

    handleNewNode() {
      const self = this
      if (self.isConfigModified()) {
        self.$confirm('节点配置已修改，是否进行保存?', '确认', {}).then(() => {
          self.handleSaveImpl().then(resolve => {
            self.nodeGraph.clearCells()
            self.initConfigOptions()
          })
        }).catch(() => {
          self.nodeGraph.clearCells()
          self.initConfigOptions()
        })
      } else {
        self.nodeGraph.clearCells()
        self.initConfigOptions()
      }
      this.currentNode = null
    },

    handleDeleteNode() {
      const self = this
      if (!self.currentNode) {
        return
      }
      self.$confirm('删除节点可能导致已保存的图形打开失败，是否继续?', '确认', {}).then(response => {
        deleteGraphNode(this.currentNode).then(response => {
          if (response.data) {
            // 从当前对话框和系统中移除节点
            const index = self.graphNodeGroups.findIndex(value => {
              return value.groupName === self.currentNode.groupName
            })
            if (index !== -1) {
              const index1 = self.graphNodeGroups[index].nodeDatas.findIndex(value => {
                return value.name === self.currentNode.name
              })
              if (index1 !== -1) {
                self.graphNodeGroups[index].nodeDatas.splice(index1, 1)
              }
            }
            UIUtil.successMessage('节点删除成功')
            self.currentNode = null
            self.initConfigOptions()
          } else {
            UIUtil.failMessage('节点删除失败')
          }
        })
      }).catch(() => { UIUtil.failMessage('节点删除失败') })
    },

    groupRowClassName({ row, rowIndex }) {
      let className = 'groupRow'
      if (this.currentNode && this.currentNode.name === row.name) {
        className = 'groupRow-select'
      }
      return className
    },

    formatNodeData(row, column, cellValue, index) {
      const jsonValue = JSON.parse(row.content)
      return jsonValue.data && jsonValue.data.desc ? jsonValue.data.desc : row.name
    },

    handleGraphRowClick(row, column, event) {
      const self = this
      if (self.currentNode) {
        if (self.currentNode.id === row.id) {
          return
        } else {
          if (self.isConfigModified()) {
            self.$confirm('节点配置已修改，是否进行保存?', '确认', {}).then(() => {
              self.handleSaveImpl().then(resolve => {
                self.changeCurrentNode(row)
              })
            }).catch(() => {
              self.changeCurrentNode(row)
            })
          } else {
            self.changeCurrentNode(row)
          }
        }
      } else {
        self.changeCurrentNode(row)
      }
    },

    changeCurrentNode(node) {
      const self = this
      self.currentNode = node
      self.setConfigOptions(self.currentNode.content)
      self.handleVerified()
    },

    handleMetaTypeChange(metaType) {
      this.form.data.metaName = ConfigUtil.getMetaTypeName(metaType)
    },

    handleViewAttrsConfig() {
      this.$refs.attrsDescDialog.showDialog()
    },

    handleVerified() {
      const nodeShape = this.form.shape
      // 取消注册节点
      Graph.unregisterNode(nodeShape)
      // 注册节点
      const options = this.getRegisterOptions()
      if (_.isEmpty(options)) {
        return
      }
      Graph.registerNode(nodeShape, options, true)
      // 显示节点
      const width = this.nodeGraph.options.width
      const height = this.nodeGraph.options.height
      const x = (width - options.width) / 2
      const y = (height - options.height) / 2
      this.nodeGraph.clearCells()
      this.nodeGraph.addNode({
        shape: nodeShape,
        x: x,
        y: y
      })
      // 取消注册节点
      Graph.unregisterNode(nodeShape)
    },

    handleSave() {
      const self = this
      self.handleSaveImpl().then(resolve => {
      }).catch(() => {})
    },

    handleSaveImpl() {
      const self = this
      return new Promise((resolve, reject) => {
        const configOption = self.getRegisterOptions()
        if (_.isEmpty(configOption)) {
          reject()
        }
        const configOptionText = ConstantUtil.stringifyJson(configOption)

        const node = {
          name: configOption.shape,
          groupName: configOption.data.group,
          content: configOptionText
        }
        if (self.currentNode) {
          node.id = self.currentNode.id
          updateGraphNode(node).then(response => {
            if (response.data) {
              self.onSaveSuccess(false, response.data)
              resolve()
            } else {
              self.onSaveFail()
              reject()
            }
          }).catch(() => {
            self.onSaveFail()
            reject()
          })
        } else {
          addGraphNode(node).then(response => {
            if (response.data) {
              self.onSaveSuccess(true, response.data)
              resolve()
            } else {
              self.onSaveFail()
              reject()
            }
          }).catch(() => {
            self.onSaveFail()
            reject()
          })
        }
      })
    },

    onSaveSuccess(isAdd, node) {
      const self = this
      const groupIndex = self.graphNodeGroups.findIndex(value => {
        return value.groupName === node.groupName
      })
      if (groupIndex === -1) {
        return
      }
      const nodeIndex = self.graphNodeGroups[groupIndex].nodeDatas.findIndex(value => {
        return value.name === node.name
      })
      if (nodeIndex === -1) {
        self.graphNodeGroups[groupIndex].nodeDatas.push(node)
      } else {
        self.graphNodeGroups[groupIndex].nodeDatas.splice(nodeIndex, 1, node)
      }
      self.currentNode = node
      // 重新加载自定义节点
      RegisterUtil.loadCustomizeNodes(self)
      UIUtil.successMessage('节点保存成功')
    },

    onSaveFail() {
      UIUtil.failMessage('节点保存失败')
    }
  }
}
</script>

<style>
.groupRow-select {
  color:coral;
  font-weight: bold;
}
.groupRow {
  color:black;
  font-weight: bold;
}
</style>

<style scoped>
.groupColumn {
  height: 500px;
}

.groupCollapse {
  height: 450px;
  overflow: auto;
}

.nodeColumn {
  height: 500px;
  overflow: auto;
}
</style>